# Makefile for Linear Layouts CUDA Implementation
# Targets RTX 4070 Super (SM_89) and compatible GPUs

# CUDA Compiler and flags
NVCC = nvcc
CUDA_ARCH = sm_89
CUDA_FLAGS = -arch=$(CUDA_ARCH) -O3 --use_fast_math -std=c++17 --expt-relaxed-constexpr
CUDA_FLAGS += -Xcompiler -Wall -Xcompiler -Wextra
CUDA_FLAGS += -lineinfo -g

# Directories
SRC_DIR = .
BUILD_DIR = build
EXAMPLES_DIR = examples
BENCHMARKS_DIR = benchmarks
TESTS_DIR = tests

# Include paths
INCLUDES = -I$(SRC_DIR) -I$(SRC_DIR)/linear_layouts_core -I$(SRC_DIR)/layouts

# Source files
CORE_HEADERS = linear_layouts_core/binary_matrix.cuh \
               linear_layouts_core/linear_layout.cuh \
               linear_layouts_core/layout_operations.cuh

LAYOUT_HEADERS = layouts/blocked_layout.cuh \
                 layouts/mma_layout.cuh \
                 layouts/swizzled_layout.cuh

ALL_HEADERS = $(CORE_HEADERS) $(LAYOUT_HEADERS)

# Example executables
EXAMPLES = $(BUILD_DIR)/layout_demo

# Test executables
TESTS = $(BUILD_DIR)/test_binary_matrix \
        $(BUILD_DIR)/test_layouts \
        $(BUILD_DIR)/test_operations

# Benchmark executables
BENCHMARKS = $(BUILD_DIR)/bench_conversion \
             $(BUILD_DIR)/bench_vectorization \
             $(BUILD_DIR)/bench_swizzling

# Default target
all: directories $(EXAMPLES)

# Create build directory
directories:
	@mkdir -p $(BUILD_DIR)

# Main example
$(BUILD_DIR)/layout_demo: $(EXAMPLES_DIR)/layout_demo.cu $(ALL_HEADERS)
	$(NVCC) $(CUDA_FLAGS) $(INCLUDES) -o $@ $<

# Individual tests
$(BUILD_DIR)/test_binary_matrix: $(TESTS_DIR)/test_binary_matrix.cu $(CORE_HEADERS)
	$(NVCC) $(CUDA_FLAGS) $(INCLUDES) -o $@ $<

$(BUILD_DIR)/test_layouts: $(TESTS_DIR)/test_layouts.cu $(ALL_HEADERS)
	$(NVCC) $(CUDA_FLAGS) $(INCLUDES) -o $@ $<

$(BUILD_DIR)/test_operations: $(TESTS_DIR)/test_operations.cu $(ALL_HEADERS)
	$(NVCC) $(CUDA_FLAGS) $(INCLUDES) -o $@ $<

# Benchmarks
$(BUILD_DIR)/bench_conversion: $(BENCHMARKS_DIR)/bench_conversion.cu $(ALL_HEADERS)
	$(NVCC) $(CUDA_FLAGS) $(INCLUDES) -o $@ $<

$(BUILD_DIR)/bench_vectorization: $(BENCHMARKS_DIR)/bench_vectorization.cu $(ALL_HEADERS)
	$(NVCC) $(CUDA_FLAGS) $(INCLUDES) -o $@ $<

$(BUILD_DIR)/bench_swizzling: $(BENCHMARKS_DIR)/bench_swizzling.cu $(ALL_HEADERS)
	$(NVCC) $(CUDA_FLAGS) $(INCLUDES) -o $@ $<

# Build all tests
tests: directories $(TESTS)

# Build all benchmarks
benchmarks: directories $(BENCHMARKS)

# Run main demo
run: $(BUILD_DIR)/layout_demo
	./$(BUILD_DIR)/layout_demo

# Run tests
test: tests
	@echo "Running binary matrix tests..."
	./$(BUILD_DIR)/test_binary_matrix
	@echo "Running layout tests..."
	./$(BUILD_DIR)/test_layouts
	@echo "Running operations tests..."
	./$(BUILD_DIR)/test_operations

# Run benchmarks
bench: benchmarks
	@echo "Running conversion benchmarks..."
	./$(BUILD_DIR)/bench_conversion
	@echo "Running vectorization benchmarks..."
	./$(BUILD_DIR)/bench_vectorization
	@echo "Running swizzling benchmarks..."
	./$(BUILD_DIR)/bench_swizzling

# Check CUDA setup
check-cuda:
	@echo "Checking CUDA installation..."
	@which nvcc || (echo "NVCC not found! Please install CUDA toolkit." && exit 1)
	@nvcc --version
	@echo "Checking GPU compatibility..."
	@nvidia-smi || (echo "nvidia-smi not found! Please install NVIDIA drivers." && exit 1)

# Check for RTX 4070 Super or compatible GPU
check-gpu:
	@echo "Checking for SM_89 compatible GPU..."
	@nvidia-smi --query-gpu=name,compute_cap --format=csv,noheader,nounits | \
	 awk -F, '$$2 >= 8.9 {found=1; print "Found compatible GPU: " $$1 " (SM_" $$2 ")"} \
	          END {if(!found) {print "Warning: No SM_89+ GPU found. Code may not run optimally."; exit 1}}'

# Compile with debug information
debug: CUDA_FLAGS += -G -DDEBUG
debug: all

# Compile for multiple architectures
multi-arch: CUDA_FLAGS += -gencode arch=compute_80,code=sm_80 \
                          -gencode arch=compute_86,code=sm_86 \
                          -gencode arch=compute_89,code=sm_89 \
                          -gencode arch=compute_90,code=sm_90
multi-arch: all

# Generate documentation (requires doxygen)
docs:
	@which doxygen || (echo "Doxygen not found! Please install doxygen." && exit 1)
	doxygen Doxyfile

# Performance profiling
profile: $(BUILD_DIR)/layout_demo
	@which nsys || (echo "Nsight Systems not found! Please install CUDA toolkit with Nsight." && exit 1)
	nsys profile --output=linear_layouts_profile ./$(BUILD_DIR)/layout_demo

# Memory checking
memcheck: $(BUILD_DIR)/layout_demo
	@which cuda-memcheck || (echo "cuda-memcheck not found! Please install CUDA toolkit." && exit 1)
	cuda-memcheck ./$(BUILD_DIR)/layout_demo

# Performance analysis
perf-analysis: $(BUILD_DIR)/layout_demo
	@which ncu || (echo "Nsight Compute not found! Please install CUDA toolkit with Nsight." && exit 1)
	ncu --set full --export linear_layouts_metrics ./$(BUILD_DIR)/layout_demo

# Clean build artifacts
clean:
	rm -rf $(BUILD_DIR)

# Clean everything including generated files
distclean: clean
	rm -f *.nsys-rep *.ncu-rep *.sqlite

# Install to system (optional)
install: all
	@echo "Installing Linear Layouts headers to /usr/local/include/linear_layouts..."
	@sudo mkdir -p /usr/local/include/linear_layouts
	@sudo cp -r linear_layouts_core /usr/local/include/linear_layouts/
	@sudo cp -r layouts /usr/local/include/linear_layouts/
	@echo "Installation complete. Include with: #include <linear_layouts/linear_layout.cuh>"

# Uninstall from system
uninstall:
	@echo "Removing Linear Layouts from /usr/local/include..."
	@sudo rm -rf /usr/local/include/linear_layouts

# Show help
help:
	@echo "Linear Layouts CUDA Implementation Build System"
	@echo "=============================================="
	@echo ""
	@echo "Targets:"
	@echo "  all           - Build main example (default)"
	@echo "  tests         - Build all tests"
	@echo "  benchmarks    - Build all benchmarks"
	@echo "  run           - Run main demo"
	@echo "  test          - Run all tests"
	@echo "  bench         - Run all benchmarks"
	@echo "  debug         - Build with debug information"
	@echo "  multi-arch    - Build for multiple GPU architectures"
	@echo "  check-cuda    - Check CUDA installation"
	@echo "  check-gpu     - Check for compatible GPU"
	@echo "  profile       - Profile with Nsight Systems"
	@echo "  memcheck      - Check for memory errors"
	@echo "  perf-analysis - Analyze performance with Nsight Compute"
	@echo "  docs          - Generate documentation"
	@echo "  clean         - Remove build artifacts"
	@echo "  distclean     - Remove all generated files"
	@echo "  install       - Install headers to system"
	@echo "  uninstall     - Remove headers from system"
	@echo "  help          - Show this help"
	@echo ""
	@echo "Environment Variables:"
	@echo "  CUDA_ARCH     - Target architecture (default: sm_89)"
	@echo "  NVCC          - CUDA compiler path (default: nvcc)"
	@echo ""
	@echo "Requirements:"
	@echo "  - CUDA Toolkit 11.0+ (12.0+ recommended)"
	@echo "  - SM_89 compatible GPU (RTX 4070 Super or newer)"
	@echo "  - C++17 compatible compiler"

# Include dependency tracking
-include $(BUILD_DIR)/*.d

.PHONY: all directories tests benchmarks run test bench check-cuda check-gpu debug multi-arch docs profile memcheck perf-analysis clean distclean install uninstall help

# Advanced build options
ifdef CUTLASS_DIR
INCLUDES += -I$(CUTLASS_DIR)/include
CUDA_FLAGS += -DUSE_CUTLASS
endif

ifdef VERBOSE
CUDA_FLAGS += --verbose
endif

ifdef FAST_MATH
CUDA_FLAGS += --use_fast_math
endif

# Conditional compilation based on GPU architecture
ifdef CUDA_ARCH
ifeq ($(CUDA_ARCH),sm_90)
CUDA_FLAGS += -DSUPPORT_WGMMA
endif
ifeq ($(CUDA_ARCH),sm_89)
CUDA_FLAGS += -DSUPPORT_ADA_FEATURES
endif
endif